#include "FilterCSV.h"

//////////////////////////////////////////////////////////////////////////
//Author	:	Ross Conroy ross.conroy@tees.ac.uk
//Date		:	04/07/2014
//
//Class used to filter CSV files into groups for later conversion to PPR
//Large CSV files are split into smaller ones based on filer parameters
//////////////////////////////////////////////////////////////////////////

FilterCSV::FilterCSV(void)
{
}

//////////////////////////////////////////////////////////////////////////
//Not specific to any filter, used to get the index of a particular header
//from the header row
//////////////////////////////////////////////////////////////////////////
int FilterCSV::GetIndexOfHeader(string headerRow, string header)
{
	string cH = headerRow;
	string temp;
	int unitIdIndex = 0;
	int lastRecIndex = 0;
	int i = 0;
	while (cH.find(",", 0) != string::npos)
	{
		size_t  pos = cH.find(",", 0);
		temp = cH.substr(0, pos);
		cH.erase(0, pos + 1);
		if(temp == header)
		{
			return i;
		}

		i++;
	}

	return -1;
}

//////////////////////////////////////////////////////////////////////////
//Not specific to any filter, used to get a string of data from a row
//given an index integer
//////////////////////////////////////////////////////////////////////////
string FilterCSV::GetDataForIndex(string row, int index)
{
	string temp;

	if(index > -1)
	{
		int i = 0;
		while (row.find(",", 0) != string::npos)
		{
			size_t  pos = row.find(",", 0);
			temp = row.substr(0, pos);
			row.erase(0, pos + 1);				

			if(i == index)
			{
				return temp;
			}

			i++;
		}
	}	

	return "";
}


//////////////////////////////////////////////////////////////////////////
//Filter specific to StarCraft csv files, returned list is a list of lists
//of strings. Each list of strings is a single battle for a given unit, so
//data structure is a list of battles
//Each list starts with the column headings from the base CSV file
//////////////////////////////////////////////////////////////////////////
list<list<string>> FilterCSV::StarcraftFilter(string unitIDCol, int unitID, string timeLastRecCol, int timeLastRecFilter,
												string attackCol, string enemyVisibleCol, string underAttackCol, list<string> rows)
{
	list<list<string>> battles;

	//ifstream csvFile(inputFile.c_str());

	string temp;
	/*list<string> rows;

	while(getline(csvFile, temp))
	{
	rows.push_back(temp);
	}*/

	if(rows.size() > 0)
	{
		//Get the index of the headings for unit ID and time since last recorded
		string colHeaders = rows.front();
		rows.pop_front();		

		int unitIdIndex = GetIndexOfHeader(colHeaders, unitIDCol);
		int lastRecIndex = GetIndexOfHeader(colHeaders, timeLastRecCol);
		int attackIndex = GetIndexOfHeader(colHeaders, attackCol);
		int visibleIndex = GetIndexOfHeader(colHeaders, enemyVisibleCol);
		int underAttackIndex = GetIndexOfHeader(colHeaders, underAttackCol);

		//Loop through data and start a new list of strings for each time the time since last
		//rec is higher than the limit set
		list<string> battle;

		while(rows.size() > 0)
		{
			string row = rows.front();
			int i = 0;

			int timeSinceLastRec = 0;
			int uID = 0;			

			uID = atoi(GetDataForIndex(row, unitIdIndex).c_str());
			timeSinceLastRec = atoi(GetDataForIndex(row, lastRecIndex).c_str());

			//Check if row for desired unit ID and time since unit last recorded
			//if new battle has started create a new string list with the column
			//headers
			if(unitID == uID)
			{
				stringstream sd;

				sd << GetDataForIndex(rows.front(), unitIdIndex) << "," << GetDataForIndex(rows.front(), attackIndex) << "," << GetDataForIndex(rows.front(), visibleIndex) << ",";
				sd << GetDataForIndex(rows.front(), underAttackIndex) << "," <<  GetDataForIndex(rows.front(), lastRecIndex) << ",";

				if(timeSinceLastRec >= timeLastRecFilter)
				{	
					stringstream sh;
					sh << unitIDCol << "," << attackCol << "," << enemyVisibleCol << "," << underAttackCol << "," << timeLastRecCol << ",";
					string newHeaders = sh.str();

					if(battle.size() > 0) //First battle will be empty
					{
						battles.push_front(battle);
					}					
					battle.clear();
					//battle.push_back(colHeaders);
					battle.push_back(newHeaders);
				}
				//battle.push_back(rows.front());
				battle.push_back(sd.str());
			}

			rows.pop_front();
		}

		battles.push_front(battle);
	}

	return battles;
}

//////////////////////////////////////////////////////////////////////////
//Specific to StrarCraft
//Returns a list of unique ids of the units in the CSV file
//////////////////////////////////////////////////////////////////////////
hash_map<int, list<string>> FilterCSV::GetListOfUnitIds(string unitIDCol, string inputFile)
{
	hash_map<int, list<string>> unitIds;
	ifstream csvFile(inputFile.c_str());	

	string temp;
	list<string> rows;

	while(getline(csvFile, temp))
	{
		rows.push_back(temp);
	}

	if(rows.size() > 0)
	{
		string colHeaders = rows.front();
		rows.pop_front();
		int unitIdIndex = GetIndexOfHeader(colHeaders, unitIDCol);

		while(rows.size() > 0)
		{
			string row = rows.front();
			int i = 0;

			int timeSinceLastRec = 0;
			int uID = 0;

			uID = atoi(GetDataForIndex(row, unitIdIndex).c_str());

			if(unitIds.find(uID) != unitIds.end())
			{
				unitIds[uID].push_back(row);
			}
			else
			{
				unitIds[uID].push_back(colHeaders);
				unitIds[uID].push_back(row);
			}

			//unitIds[uID] = uID;

			rows.pop_front();
		}
	}

	return unitIds;
}


//////////////////////////////////////////////////////////////////////////
//Compresses the time-steps as time between steps recorded in milliseconds
//and a data point is recorded once per frame of the game so approx 40ms
//between steps.
//////////////////////////////////////////////////////////////////////////
list<list<string>> FilterCSV::CompressBattlesTimeSteps(list<list<string>> battles, int timeStepDuration, string timeStepCol,
	string unitIDCol, string attackCol, string enemyVisibleCol, string underAttackCol)
{
	list<list<string>> compressedBattles;

	for(list<list<string>>::iterator it = battles.begin(); it != battles.end(); it++)
	{
		list<string> battle = *it;
		list<string> compressedBattle;

		string colheaders = battle.front();
		int timeIndex = GetIndexOfHeader(colheaders, timeStepCol);
		int unitIdIndex = GetIndexOfHeader(colheaders, unitIDCol);
		int attackIndex = GetIndexOfHeader(colheaders, attackCol);
		int enemyVisIndex = GetIndexOfHeader(colheaders, enemyVisibleCol);
		int underAttackIndex = GetIndexOfHeader(colheaders, underAttackCol);

		int unitId;
		bool hasAttacked = false;
		bool enemyVisible = false;
		bool wasAttacked = false;
		int timeIncrement = 0;

		for(list<string>:: iterator itb = battle.begin(); itb != battle.end(); itb++)
		{
			string row = *itb;

			if(row != colheaders)
			{
				int time = atoi(GetDataForIndex(row, timeIndex).c_str());
				timeIncrement += time;

				int attack = atoi(GetDataForIndex(row, attackIndex).c_str());
				if(attack == 1)
				{
					hasAttacked = true;
				}

				int visible = atoi(GetDataForIndex(row, enemyVisIndex).c_str());
				if(visible == 1)
				{
					enemyVisible = true;
				}

				int attacked = atoi(GetDataForIndex(row, underAttackIndex).c_str());
				if(attacked == 1)
				{
					wasAttacked = true;
				}

				//end of time step
				if(timeIncrement >= timeStepDuration)
				{
					unitId = atoi(GetDataForIndex(row, unitIdIndex).c_str());

					stringstream sd;
					sd << unitId << "," << hasAttacked << "," << enemyVisible << ",";
					sd << wasAttacked << "," <<  timeIncrement << ",";

					compressedBattle.push_back(sd.str());

					hasAttacked = false;
					enemyVisible = false;
					wasAttacked = false;
					timeIncrement = 0;
				}
			}
			else
			{
				compressedBattle.push_back(row);
			}
		}

		compressedBattles.push_back(compressedBattle);
	}

	return compressedBattles;
}